package com.sage.logbook.server;

import java.io.ByteArrayOutputStream;
import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.proxy.ProxyServlet;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import com.sage.logbook.config.ServerConfig;
import com.sage.logbook.queue.DataQueue;
import com.sage.logbook.queue.Session;

/**
 * リバースプロキシ
 *
 */
@SuppressWarnings("serial")
public final class ReverseProxyServlet extends ProxyServlet {

    private static final String REQUEST_BODY = "req-body";
    private static final String RESPONSE_BODY = "res-body";

    @Override
    protected void customizeProxyRequest(Request proxyRequest, HttpServletRequest request) {
        proxyRequest.onRequestContent((proxy, buffer) -> request.setAttribute(REQUEST_BODY, Arrays.copyOf(buffer.array(), buffer.limit())));
        proxyRequest.onRequestSuccess(req -> request.setAttribute(RESPONSE_BODY, new ByteArrayOutputStream(1 << 19)));
    }

    /*
     * VIA ヘッダーを除去します
     */
    @Override
    protected Request addViaHeader(Request proxyRequest) {
        return proxyRequest;
    }

    /*
     * Hop-by-Hop ヘッダーを除去します
     */
    @Override
    protected void addXForwardedHeaders(Request proxyRequest, HttpServletRequest request) {
        // Do nothing
    }

    /*
     * レスポンスが帰ってきた
     */
    @Override
    protected void onResponseContent(HttpServletRequest request, HttpServletResponse response, Response proxyResponse, byte[] buffer, int offset, int length, Callback callback) {
        ByteArrayOutputStream stream = (ByteArrayOutputStream) request.getAttribute(RESPONSE_BODY);
        stream.write(buffer, offset, length);

        super.onResponseContent(request, response, proxyResponse, buffer, offset, length, callback);
    }

    /*
     * レスポンスが完了した
     */
    @Override
    protected void onResponseSuccess(HttpServletRequest request, HttpServletResponse response, Response proxyResponse) {
        byte[] postdata = (byte[]) request.getAttribute(REQUEST_BODY);
        ByteArrayOutputStream responsedata = (ByteArrayOutputStream) request.getAttribute(RESPONSE_BODY);

        String contentType = proxyResponse.getHeaders().get(HttpHeader.CONTENT_TYPE);
        String contentEncoding = proxyResponse.getHeaders().get(HttpHeader.CONTENT_ENCODING);

        Session session = new Session(request.getRequestURI(), postdata, responsedata.toByteArray(), contentType, contentEncoding);
        DataQueue.push(session);

        super.onResponseSuccess(request, response, proxyResponse);
    }

    /*
     * HttpClientを作成する
     */
    @Override
    protected HttpClient newHttpClient() {
        SslContextFactory sslContextFactory = new SslContextFactory();

        HttpClient client = new HttpClient(sslContextFactory);
        // プロキシを設定する
        if (ServerConfig.useProxy()) {
            // ポート
            int port = ServerConfig.getProxyPort();
            // ホスト
            String host = ServerConfig.getProxyHost();
            // 設定する
            client.getProxyConfiguration().getProxies().add(new HttpProxy(host, port));
        }
        return client;
    }
}
